<template>
  <a-card title="Redis管理">
    <a-spin :spinning="pushing">
      <a-row :gutter="8">
        <a-col :span="6" style="padding-right: 5px">
          <span>选择DB实例：</span> 
          <a-select v-model="redisDB" style="width: 120px">
            <a-select-option v-for="v in redisDBList" :key="v" :value="v">{{ v }}</a-select-option>
          </a-select>
          <div style="margin-top: 5px;height: 450px;overflow: scroll;border:1px solid #a5b6c8;border-left-width: 0; border-right-width: 1px">
            <s-tree
              showIcon
              :dataSource="orgTree"
              @add="handleAdd"
              @click="handleClick">
            </s-tree>
          </div>
        </a-col>
        <a-col :span="18">
          <codemirror ref="myCm" :options="cmOptions"></codemirror>
        </a-col>
      </a-row>
      <a-row>
        <a-col :span="24">
          <a-auto-complete @select="onSelect" @search="handleSearch">
            <template slot="dataSource">
              <a-select-option disabled key="null" v-if="dataSource.length > 0">可执行以下命令</a-select-option>
              <a-select-option v-for="v in dataSource" :key="v">{{ v }}</a-select-option>
            </template>
            <a-textarea
              style="margin: 5px;height: 100px;width: 1000px;"
              v-model="redis_cmd"
              @keydown.tab.native="handleKeyTab"
              placeholder="输入执行命令..." />
          </a-auto-complete>
        </a-col>
        <a-col :span="24">
          <a-button style="top: 10px;left: 10px;" type="primary" size="large" @click="handleCmd">执行</a-button>
        </a-col>
      </a-row>
    </a-spin>
    <a-modal v-model="visibleModal" :footer="null" title="实例统计信息" width="60%">
      <a-spin tip="Loading..." :spinning="spin">
        <a-descriptions bordered size="small" :column="2" >
          <a-descriptions-item label="实例" :span="2">
            <span>{{ redisTitle }}</span>
          </a-descriptions-item>
          <a-descriptions-item label="状态" :span="2">
            <a-badge status="processing" text="Running" />
          </a-descriptions-item>
          <a-descriptions-item v-for="(v, k) in redisMetrics" :key="k" :value="v" :label="k">
            <span>{{ v }}</span>
          </a-descriptions-item>
        </a-descriptions>
      </a-spin>
    </a-modal>
  </a-card>
</template>

<script>
import STree from '@/components/Tree/Tree'
import redisApi from "@/api/redisms.js"

import 'codemirror/theme/material.css'
import "codemirror/mode/javascript/javascript"
import "codemirror/addon/selection/active-line"
import "codemirror/addon/display/autorefresh"
import "codemirror/keymap/sublime"
import notification from 'ant-design-vue/es/notification'



export default {
  name: 'RedisList',
  components: {
    STree,
  },
  data () {
    return {
      orgTree: [],
      result: [],
      openKeys: null,
      redis_cmd: null,
      redisDB: 0,
      redisDBList: [...new Array(16).keys()],
      redisMetrics: null,
      pushing: false,
      spin: false,
      visibleModal: false,
      redisCmds: [],
      dataSource: [],
      redisTitle: '',
      cmOptions: {
        mode: "text/x-shell",
        readOnly: true,
        autoRefresh: true,
        autofocus: false,
        keyMap: "sublime", // 编辑器模式
        autoCloseBrackets: true,
        lineWrapping: true, // 代码折叠
        foldGutter: true,
        theme: "material",
        gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"]
      },
    }
  },
  created () {
    this.fetchRedisIns()
    this.getRedisCmdList()
  },
  mounted() {
    this.$refs.myCm.codemirror.setValue("查询结果输出 ...")
  },
  computed: {
    codemirror() {
      return this.$refs.myCm.codemirror
    }
  },
  methods: {
    fetchRedisIns() {
      redisApi.getRedisIns().then(resp => {
        this.orgTree = resp.data
      }).catch(error => {
        notification.error({
          message: 'error',
          description: "无法加载redis列表"
        })
      })
    },
    getRedisCmdList() {
      redisApi.getRedisCmdList().then(resp => {
        this.redisCmds = resp.data
      })
    },
    handleClick (e) {
      this.openKeys = e.key
      //console.log(this.$refs.myCm.codemirror)
    },
    handleAdd(e) {
      this.redisTitle = e.title
      this.redisMetrics = null
      this.spin = true
      redisApi.getRedisCmd(e.key, this.redisDB).then(resp => {
        this.redisMetrics = resp.data
      }).catch(error => {
        notification.error({
          message: 'error',
          description: "无法加载redis Metrics"
        })
      }).finally(() => {
        this.spin = false
      })
      this.visibleModal = true
    },
    onSelect(value) {
      this.redis_cmd = value
    },
    handleSearch(value) {
      this.dataSource = []
      if(value && value.length >1){
        for(var i in this.redisCmds) {
          if(this.redisCmds[i].indexOf(value)>=0){
            this.dataSource.push(this.redisCmds[i])
          }
        }
      }
    },
    handleKeyTab(e) {
      e.preventDefault()
      if(this.dataSource.length > 0) {
        e.target.value = this.dataSource[0]
      }
    },
    handleCmd() {
      if(this.openKeys === null){
        this.$message.error("请先选择redis实例")
        return false
      }

      if(this.redis_cmd === null){
        this.$message.error("无效的执行命令")
        return false
      }
      const data = {
        "redis_id": this.openKeys,
        "redis_cmd": this.redis_cmd,
        "redis_db": this.redisDB,
      }
      this.pushing = true
      redisApi.execRedisCmd(data).then(resp => {
        if(resp.code === "0000") {
          const data = resp.data
          for(var item of data["data"]) {
            const formatResult = data["redis_name"]+ "> " +item["redis_cmd"]+ "\n" +this.formatData(item["result"], true)+"\n"
            this.result.push(formatResult)
          }
          this.$refs.myCm.codemirror.setValue(this.result.join(""))
          this.$refs.myCm.codemirror.scrollTo(0, this.$refs.myCm.codemirror.doc.height) //移动右侧滚动条
        } else {
          this.$message.error(resp.message)
        }
      }).catch(error => {
        this.$message.error("内部错误")
      }).finally(() => {
        this.pushing = false
      })
    },
    formatData(obj, flag) {
      if (!obj && typeof(obj) != "undefined" && obj !== 0) {
        return "None"
      } else if ((typeof(obj) == "object") && obj.constructor === Array) {
        let obj_str = ""
        if(obj.length === 0){
          obj_str = "[]\n" 
        } else {
          for (const [k, value] of Object.entries(obj)) {
            const key = parseInt(k)
            if (flag) {
              obj_str += (key + 1) + ") " + this.formatData(value, false) + "\n"
            } else if (key === 0) {
              obj_str += (key + 1) + ") " + this.formatData(value) + "\n"
            } else {
              obj_str += "   "+ (key + 1) + ") " + this.formatData(value) + "\n"
            }
          }
        }
        return obj_str
      } else if ((typeof(obj) == "object") && obj.constructor === Object) {
        let obj_str = ""
        if (Object.keys(obj).length === 0) {
          obj_str = "{}\n"
        } else {
          for (const [key, value] of Object.entries(obj)) {
            if (flag) {
              obj_str += "  "+ key + ": " + this.formatData(value, false) + "\n"
            } else {
              obj_str += key + "=" + this.formatData(value, false) + ","
            }
          }
        }
        return obj_str
      } else {
        return obj
      }
    }
  }
}
</script>

<style lang="less">
  .custom-tree {

    /deep/ .ant-menu-item-group-title {
      position: relative;
      &:hover {
        .btn {
          display: block;
        }
      }
    }

    /deep/ .ant-menu-item {
      font-size: 12px;
      &:hover {
        .btn {
          display: block;
        }
      }
    }

    /deep/ .btn {
      display: none;
      position: absolute;
      top: 0;
      right: 10px;
      width: 20px;
      height: 40px;
      line-height: 40px;
      z-index: 1050;

      &:hover {
        transform: scale(1.2);
        transition: 0.5s all;
      }
    }
  }
  
  .CodeMirror {
    border: 1px solid #eee;
    height: 487px;
    font-size: 13px;
  }

  .spin-content {
    border: 1px solid #91d5ff;
    background-color: #e6f7ff;
    padding: 30px;
  }

  .ant-form-item-control {
    height: 10;
    line-height: 10px;
  }

  .ant-select-search__field__wrap { 
    overflow: hidden;
  }

</style>